/**
 * @p.md
 * 
 * PID（Process ID）类，表示一个唯一的 Actor 进程标识符
 */
import { ActorSystem } from './actorSystem';
import { Future } from './future';
import { DeadLetterEvent } from './eventStream';

/**
 * 消息类型字符串
 */
type MessageType = 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | 'null' | 'array' | string;

/**
 * PID 类表示一个 Actor 进程的唯一标识符
 * 包含地址和 ID 两部分
 */
export class PID {
  public system?: ActorSystem;
  
  /**
   * 创建一个新的 PID
   * @param address 地址部分，通常是主机名+端口号，如 "localhost:12001" 或 "local"（本地）
   * @param id ID 部分，通常是 Actor 实例的唯一标识
   */
  constructor(public readonly address: string, public readonly id: string) { }
  
  /**
   * 获取 PID 的完整字符串表示
   */
  toString(): string {
    return `${this.address}/${this.id}`;
  }
  
  /**
   * 向 PID 发送消息
   * @param message 要发送的消息
   * @param sender 发送者系统（用于处理远程消息）
   */
  tell(message: any, sender: ActorSystem): void {
    if (!sender) {
      console.warn(`[PID] 警告: 发送消息到 ${this.toString()} 时没有提供系统引用`);
      return;
    }
    
    console.log(`[PID] 向 ${this.toString()} 发送消息`);
    
    const registry = sender.processRegistry;
    const reff = registry.get(this);
    
    if (reff) {
      console.log(`[PID] 找到进程，将发送消息`);
      reff.sendUserMessage(this, message);
    } else {
      console.log(`[PID] 进程未找到，将发布 DeadLetter 事件: ${this.toString()}`);
      
      // 检查是否为远程地址
      if (this.address !== 'local' && this.address !== registry.address()) {
        console.log(`[PID] 检测到远程地址 ${this.address}，尝试远程发送...`);
        
        // 尝试通过 Remote 发送
        try {
          // 检查是否可以访问 Remote 组件
          const remote = (sender as any).remote;
          if (remote && typeof remote.sendRemoteMessage === 'function') {
            console.log(`[PID] 通过远程系统发送消息到 ${this.toString()}`);
            remote.sendRemoteMessage(this, message);
            return; // 消息已通过远程系统发送，不需要发布 DeadLetter
          } else {
            console.warn(`[PID] 系统没有可用的远程组件，无法发送到 ${this.toString()}`);
          }
        } catch (error) {
          console.error(`[PID] 远程发送失败:`, error);
        }
      }
      
      // 如果远程发送失败或不是远程地址，发布 DeadLetter 事件
      this.publishDeadLetter(sender, message);
    }
  }

  /**
   * 发布 DeadLetter 事件
   * @param system Actor 系统
   * @param message 消息
   * @param sender 发送者（可选）
   */
  private publishDeadLetter(system: ActorSystem, message: any, sender?: PID): void {
    if (!system) return;
    
    console.log(`[PID] Process not found for ${this.toString()}, publishing DeadLetter event`);
    
    let type: MessageType = typeof message;
    if (message === null) {
      type = "null";
    } else if (message === undefined) {
      type = "undefined";
    } else if (Array.isArray(message)) {
      type = "array";
    } else if (typeof message === "object") {
      type = message.constructor ? message.constructor.name : "object";
    }
    
    const event = new DeadLetterEvent(
      this.toString(), 
      !!sender, 
      sender ? sender.toString() : '', 
      type
    );
    
    system.eventStream.publish(event);
    console.log(`[PID] DeadLetter event published`);
  }
  
  /**
   * 创建带有系统引用的新 PID
   * @param address 地址
   * @param id ID
   * @param system 系统引用
   */
  static fromAddress(address: string, id: string, system?: ActorSystem): PID {
    const pid = new PID(address, id);
    pid.system = system;
    return pid;
  }
  
  /**
   * 检查 PID 是否为远程 PID
   * @param registry 进程注册表
   */
  isRemote(registry: any): boolean {
    return this.address !== 'local' && this.address !== registry.address();
  }

  /**
   * 向 Actor 发送一个请求，期望得到响应
   * @param message 要发送的消息
   * @param system Actor 系统
   */
  request(message: any, system: ActorSystem): void {
    const sender = system.processRegistry.hostResolverPid;
    if (!sender) {
      throw new Error('No sender available for request');
    }
    
    const envelope = {
      message,
      sender
    };
    
    system.processRegistry.get(this)?.sendUserMessage(this, envelope);
  }

  /**
   * 向 Actor 发送一个请求，并返回一个 Future 对象以获取响应
   * @param message 要发送的消息
   * @param timeout 超时时间（毫秒）
   * @param system Actor 系统
   * @returns 包含响应的 Future 对象
   */
  requestFuture(message: any, timeout: number, system: ActorSystem): Future {
    console.log(`[PID] Creating future for request to ${this.address}/${this.id}, timeout: ${timeout}ms`);
    
    // 创建 Future 实例，传入 system 和 timeout
    const future = new Future(system, timeout);
    console.log(`[PID] Future created with PID: ${future.getPID().address}/${future.getPID().id}`);
    
    // 创建消息信封
    const envelope = {
      message,
      sender: future.getPID() // 使用 getPID() 方法获取 PID
    };
    console.log(`[PID] Created envelope with sender: ${envelope.sender.address}/${envelope.sender.id}`);
    
    try {
      // 获取目标进程
      const targetProcess = system.processRegistry.get(this);
      console.log(`[PID] Target process type: ${targetProcess ? typeof targetProcess : 'undefined'}`);
      
      // 检查是否找到了目标进程
      if (!targetProcess) {
        // 如果目标进程不存在，尝试通过 Remote 发送
        if (this.address !== 'local' && this.address !== system.processRegistry.address()) {
          console.log(`[PID] Process not found locally, trying Remote for ${this.address}/${this.id}`);
          
          // 检查 Remote 是否可用
          const remote = (system as any).remote;
          if (remote && typeof remote.sendRemoteMessage === 'function') {
            console.log(`[PID] Using Remote to send message to ${this.address}/${this.id}`);
            remote.sendRemoteMessage(this, envelope);
            console.log(`[PID] Message sent via Remote`);
            return future;
          } else {
            console.warn(`[PID] Remote component not available in ActorSystem`);
          }
        }
        
        // 如果没有 Remote 或不是远程地址，发布死信事件
        console.warn(`[PID] Process not found for ${this.address}/${this.id}, publishing DeadLetter event`);
        system.eventStream.publish(new DeadLetterEvent(this.toString(), false, '', typeof message));
        console.log(`[PID] DeadLetter event published`);
        throw new Error(`Process not found for ${this.address}/${this.id}`);
      }
      
      // 如果找到目标进程
      console.log(`[PID] Process found for ${this.address}/${this.id}, sending message`);
      console.log(`[PID] Target process properties: ${Object.keys(targetProcess).join(', ')}`);
      
      // 检查是否是 PID 实例 (只有 address, id, system 属性)
      if (targetProcess instanceof PID || 
          (Object.keys(targetProcess).length <= 3 && 
           'address' in targetProcess && 
           'id' in targetProcess)) {
        console.log(`[PID] Target appears to be a PID instance, not a Process`);
        
        // 尝试通过 Remote 发送
        const remote = (system as any).remote;
        if (remote && typeof remote.sendRemoteMessage === 'function') {
          console.log(`[PID] Using Remote to send message to ${this.address}/${this.id}`);
          remote.sendRemoteMessage(this, envelope);
          console.log(`[PID] Message sent via Remote`);
          return future;
        } else {
          console.error(`[PID] Target is a PID but Remote is not available`);
          throw new Error(`Cannot send message to PID ${this.toString()}: Remote not available`);
        }
      }
      
      // 尝试不同的消息发送方法
      if (typeof targetProcess.sendUserMessage === 'function') {
        // 标准 Process 接口
        console.log(`[PID] Using standard sendUserMessage method`);
        targetProcess.sendUserMessage(this, envelope);
      } 
      else if (typeof (targetProcess as any).routeMessage === 'function') {
        // ClusterRouter 实现
        console.log(`[PID] Using ClusterRouter routeMessage method`);
        (targetProcess as any).routeMessage(this, envelope, false);
      }
      else if (typeof (targetProcess as any).send === 'function') {
        // 通用发送方法
        console.log(`[PID] Using generic send method`);
        (targetProcess as any).send(this, envelope);
      }
      else {
        // 没有找到可用的发送方法
        console.error(`[PID] No compatible message sending method found. Available properties: ${Object.keys(targetProcess).join(', ')}`);
        throw new Error(`Process does not implement required message sending methods`);
      }
      
      console.log(`[PID] Message sent to process`);
    }
    catch (error) {
      console.error(`[PID] Error sending message:`, error);
      // 错误不要抛出，让 Future 超时处理
    }
    
    return future;
  }

  /**
   * 停止 Actor
   * @param system Actor 系统
   */
  stop(system: ActorSystem): void {
    system.processRegistry.get(this)?.stop(this);
  }
} 